/* -*- jde -*- */
/* <Stack.java> */
package Practica5.structures;

/**
 * Clase que implementa una representación rápida de pilas
 *
 * @author  Peralta Santa Anna Victor Miguel
 * @since	Julio 2011
 */
public class Stack<Type> {

    /**
     * Clase Interna para la representación de los nodos de la pila
     * @param <T> el objeto del tipo T a guardar
     */
    protected class Node<T> {

        /**
         * Objeto del tipo T, elemento del nodo
         */
        public T data;
        /**
         * Nodo siguiente
         */
        public Node<T> next;

        /**
         * Contructor de un nodo
         * @param data el objeto de tipo T a almacenar.
         */
        public Node(T data) {
            this.data = data;
            next = null;
        }
    } // Node Class

    /**
     * Iterador para la clase del Stack
     *
     * @param <S> el objeto a pasar al iterador.
     */
    protected class Iterator<S> {

        /**
         * El Nodo para el iterador
         */
        public Node<S> current;

        /**
         * constructor con un nodo inicio
         * @param head el primer nodo para el iterador
         */
        public Iterator(Node<S> head) {
            current = head;
        }

        /**
         * Saber si tiene siguiente elemento
         * @return verdadero en caso de ser cierto, falso en caso contrario
         */
        public boolean hasNext() {
            return current != null;
        }

        /**
         * Hace que se avance un elemento
         */
        public void next() {
            current = current.next;
        }

        /**
         * Recupera el elemento del nodo actual.
         * @return el nodo actual
         */
        public S retrive() {
            return (S) current.data;
        }
    } // Iterator
    /**
     * El tope de la pila
     */
    public Node<Type> peek;
    /**
     * El tamaño de la pila
     */
    private long size;		// tamaño de la pila

    /**
     * Constructor sin parametros para el stack
     */
    public Stack() {
        peek = null;
        size = 0;
    }

    /**
     * Push // mete un nodo a la pila.
     * @param obj el tipo de elemento q se le va a meter del tipo Type
     */
    public void push(Type obj) {
        Node<Type> node = new Node<Type>(obj);
        node.next = peek;
        peek = node;
        size++;
    }

    /**
     * Pop // saca un nodo de la pila;
     */
    public Type pop() throws StackException {
        if (peek != null) {
            Type obj = peek.data; 	// el elemento del peek
            peek = peek.next;		// botamos el ultimo q ingreso
            size--;			// se decrementa el tamaño
            return obj;
        } else {
            throw new StackException("Empty Stack -pop()-");
        }
    }

    /**
     * Peek // regresa el elemento del nodo en el tope de la pila;
     */
    public Type peek() throws StackException {
        if (peek != null) {
            return peek.data;
        } else {
            throw new StackException("Empty Stack -peek()-");
        }
    }

    /**
     * isEmpty // regresa si la pila esta vacia.
     */
    public boolean isEmpty() {
        return peek == null;
    }

    /**
     * size // regresa el tamaño de la pila.
     */
    public long size() {
        return size;
    }

    /**
     * Generamos un iterador para la pila.
     */
    public Iterator<Type> iterator() {
        return new Iterator(peek);
    }
} // Stack class

